/*
 * Created on 24/12/2012 - 2:24 PM
 */
package sembr.vtk.reader;

import vtk.*;

/**
 *
 * @author adriano
 */
public class PngReader extends ReaderBase
{    
    private String fieldComponent;
    private vtkPNGReader reader;  
    private vtkDataSetMapper imageDataMapper;
    private vtkPolyDataMapper polyDataMapper;
    private vtkActor outlineActor;
    private vtkActor imageActor;
    private vtkCanvas panel;
    private vtkImagePlaneWidget imagePlaneWidget;
    private vtkOutlineFilter outlineFilter;
    private vtkScalarBarActor barActor; 
    private vtkImplicitPlaneWidget2 planeWidget;
    private vtkStringArray fileNames;
    private double[] fieldRange;
    private vtkPlane cutPlane;
    
    public PngReader(String fieldComponent, vtkStringArray fileNames, double fieldRange[])
    {
        setFieldComponent(fieldComponent);
        this.fileNames = fileNames;
        setFieldRange(fieldRange);
        setPngReader(new vtkPNGReader());
        setOutLineFilter(new vtkOutlineFilter());
        setImageDataMapper(new vtkDataSetMapper());        
        setPolyDataMapper(new vtkPolyDataMapper());
        setImageActor(new vtkActor());
        setOutlineActor(new vtkActor()); 
        setBarLegend(new vtkScalarBarActor());
        setPanel(new vtkCanvas());      
    }  
    
    public PngReader(String fieldComponent, vtkStringArray fileNames, double fieldRange[], boolean isCutting)
    {        
        setFieldComponent(fieldComponent);
        this.fileNames = fileNames;
        setFieldRange(fieldRange);
        setPngReader(new vtkPNGReader());
        setOutLineFilter(new vtkOutlineFilter());
        setImageDataMapper(new vtkDataSetMapper());        
        setPolyDataMapper(new vtkPolyDataMapper());
        setImageActor(new vtkActor());
        setOutlineActor(new vtkActor()); 
        setBarLegend(new vtkScalarBarActor());
        setPanel(new vtkCanvas());
        
        if (isCutting)
        {
            setPlaneWidget(new vtkImplicitPlaneWidget2());
            processReader();  
        }
        else
        {
            setImagePlaneWidget();  
        }
    } 
    
    /**
     * @return the fieldComponent
     */
    public String getFieldComponent() 
    {
        return fieldComponent;
    }
    
    /**
     * @return the fieldRange
     */
    public double[] getFieldRange() 
    {
        return fieldRange;
    }
    
   /**
     * @return the panel
     */
    public vtkCanvas getPanel() 
    {
        return panel;
    }
        
    @Override
    public vtkPolyData getPolyData() 
    {
        return outlineFilter.GetOutput();
    }
    
    /**
     * @return the imageDataMapper
     */
    public vtkDataSetMapper getImageDataMapper() 
    {
        return imageDataMapper;
    }
    
    /**
     * @return the planeWidget
     */
    public vtkImplicitPlaneWidget2 getPlaneWidget() 
    {
        return planeWidget;
    }
       
    /**
     * @param fieldComponent the fieldComponent to set
     */
    private void setFieldComponent(String fieldComponent) 
    {
        this.fieldComponent = fieldComponent;
    }
    
    /**
     * @param fieldRange the fieldRange to set
     */
    private void setFieldRange(double[] fieldRange) 
    {
        this.fieldRange = fieldRange;
    }
    
    private void setPngReader(vtkPNGReader reader)
    {   
        // TODO: doing test yet
        this.reader = reader;
        //String prefix = path + File.separator + "post_processing/" + getFieldComponent() + "-000000.00." + getDimension();
        //String prefix = path + File.separator + "post_processing/";
        //this.reader.SetFilePrefix(prefix); 
        //this.reader.SetDataByteOrderToBigEndian();
        //this.reader.SetDataExtent(0, getNrOfPixelsInX() - 1, 0, getNrOfPixelsInY() - 1, getDepthBounds()[0], getDepthBounds()[1] - 1);
        this.reader.SetFileNames(fileNames);
        //this.reader.SetDataExtent(0, 194, 0, 104, 30, 30);
        //this.reader.SetFilePattern("%s%02d.png");                
        //this.reader.Update();
        //this.reader.SetFilePattern("%s%3d.png");  
        
        this.reader.Update();    
        //int[] GetExtent = this.reader.GetOutput().GetExtent();
        //String GetFileExtensions = this.reader.GetFileExtensions();
    }
        
    private void setOutLineFilter(vtkOutlineFilter outlineFilter)
    {
        this.outlineFilter = outlineFilter;
        this.outlineFilter.SetInput(this.reader.GetOutput());
        this.outlineFilter.Update();
    }
    
    /**
     * @param imageDataMapper the imageDataMapper to set
     */
    private void setImageDataMapper(vtkDataSetMapper imageDataMapper) 
    {
        this.imageDataMapper = imageDataMapper;
        this.imageDataMapper.SetInput(this.reader.GetOutput());       
        this.imageDataMapper.SetColorModeToDefault();       
        this.imageDataMapper.Update();
    }
    
    private void setPolyDataMapper(vtkPolyDataMapper polyDataMapper)
    {
        this.polyDataMapper = polyDataMapper;
        this.polyDataMapper.SetInput(getPolyData());
        this.polyDataMapper.Update();
    }
    
    private void setOutlineActor(vtkActor outlineActor)
    {        
        this.outlineActor = outlineActor;
        this.outlineActor.SetMapper(polyDataMapper);
        // black color for outlineActor
        this.outlineActor.GetProperty().SetColor(0., 0., 0.);
    }
    
    private void setImageActor(vtkActor imageActor)
    {
        this.imageActor = imageActor;       
        this.imageActor.SetMapper(getImageDataMapper());
    }
    
    private void setPanel(vtkCanvas panel)
    {
        this.panel = panel;
        
       // TODO: ajustar image actor apenas para o MPB
      //if (imageActor != null)
      //   this.panel.GetRenderer().AddActor(imageActor);
        
        if (outlineActor != null)
            this.panel.GetRenderer().AddActor(outlineActor);      
        
        if (barActor != null)
            this.panel.GetRenderer().AddActor(barActor);
        
        // set panel's background
        this.panel.GetRenderer().SetBackground(0.1, 0.2, 0.4);
        //this.panel.GetRenderer().SetBackground(0., 0., 0.);
        // reset active camera
        this.panel.GetRenderer().ResetCamera();
    }
     
    private void setImagePlaneWidget()
    {
        vtkImageData imageData = this.reader.GetOutput();
        int[] defaultSliceIndex = setDefaultSliceIndex(imageData.GetExtent());
        vtkImageMapToColors mapToColors = new vtkImageMapToColors();        
        mapToColors.SetInput(imageData);    
                        
        for (int i = 0; i < 3; i++)
        {            
            mapToColors = new vtkImageMapToColors();    
            mapToColors.SetInput(imageData);
                       
            imagePlaneWidget = new vtkImagePlaneWidget();    
            imagePlaneWidget.GlobalWarningDisplayOff();
            imagePlaneWidget.SetDefaultRenderer(panel.GetRenderer());
            imagePlaneWidget.SetInteractor(panel.getRenderWindowInteractor());        
            imagePlaneWidget.SetKeyPressActivationValue('x'); 
            imagePlaneWidget.RestrictPlaneToVolumeOn();        
            imagePlaneWidget.SetColorMap(mapToColors);
            imagePlaneWidget.TextureInterpolateOff();
            imagePlaneWidget.SetResliceInterpolateToNearestNeighbour();
            imagePlaneWidget.SetInput(imageData);
            imagePlaneWidget.SetPlaneOrientation(i);
            imagePlaneWidget.SetSliceIndex(defaultSliceIndex[i]);  
            imagePlaneWidget.DisplayTextOn();
            imagePlaneWidget.On();
            imagePlaneWidget.InteractionOn();            
        }
    }
    
    /**
     * @param planeWidget the planeWidget to set
     */
    private void setPlaneWidget(vtkImplicitPlaneWidget2 planeWidget) 
    {
        this.planeWidget = planeWidget;
    }
    
    private int[] setDefaultSliceIndex(int[] extent)
    {
        int[] slicesByImageExtent = new int[3];

        int xAxisExtentLength = extent[1] - extent[0];
        slicesByImageExtent[0] = extent[0] + ((xAxisExtentLength + 1) / 2);

        int yAxisExtentLength = extent[3] - extent[2];
        slicesByImageExtent[1] = extent[2] + ((yAxisExtentLength + 1) / 2);

        int zAxisExtentLength = extent[5] - extent[4];
        slicesByImageExtent[2] = extent[4] + ((zAxisExtentLength + 1) / 2);

        return slicesByImageExtent;
    }
    
    private void processReader()
    {        
        createScene(reader.GetOutput());
    }
    
    private void createScene(vtkImageData imageData)
    { 
        double[] origin = {255, 15, 0};
        vtkPlane cutPlane1 = new vtkPlane();
        cutPlane1.SetOrigin(origin);
        cutPlane1.SetNormal(-3.3, -3.3, 0.);
                     
        // testing for vtkImplicitPlaneWidget
        vtkImplicitPlaneRepresentation impPlaneRep = new vtkImplicitPlaneRepresentation();
        impPlaneRep.SetPlaceFactor(1.15);
        impPlaneRep.PlaceWidget(imageData.GetBounds());
        impPlaneRep.SetNormal(cutPlane1.GetNormal());
        impPlaneRep.SetOrigin(origin);
        
        getPlaneWidget().SetInteractor(panel.getRenderWindowInteractor());
        getPlaneWidget().SetRepresentation(impPlaneRep);
        getPlaneWidget().On();  
               
        if (imageActor != null)
            this.panel.GetRenderer().AddActor(imageActor);       
    }
    
    private void setBarLegend(vtkScalarBarActor barActor)
    {      
        this.barActor = barActor;
        this.barActor.SetLookupTable(getLookupTable());
        this.barActor.GetTitleTextProperty().BoldOff();
        this.barActor.SetTitle(getFieldComponent());   
        this.barActor.GetLabelTextProperty().SetFontSize(25);
        
        //this.barActor.GetLabelTextProperty().SetFontFamilyToArial();
        this.barActor.SetNumberOfLabels(5);
        this.barActor.SetWidth(0.06);
        this.barActor.SetHeight(0.83);    
    }
    
     /**
     * @param cutPlane the cutPlane to set
     */
    private void setCutPlane() 
    {
        this.getPlaneWidget().GetImplicitPlaneRepresentation().UpdatePlacement();
        double[] origin = this.getPlaneWidget().GetImplicitPlaneRepresentation().GetOrigin();
        double[] normal = this.getPlaneWidget().GetImplicitPlaneRepresentation().GetNormal();
                
        double[] tempOrigin = {255, 0, 0};
        double[] tempNormal = {-3.476, -3.3, 0.};
        
        cutPlane = new vtkPlane();
        
        if (origin == null)
            this.cutPlane.SetOrigin(tempOrigin);
        else      
            this.cutPlane.SetOrigin(origin);
        
        if (normal == null)
            this.cutPlane.SetNormal(tempNormal);
        else
            this.cutPlane.SetNormal(normal);
    }  
    
    private vtkLookupTable getLookupTable()
    {
        vtkLookupTable lookupTable = new vtkLookupTable();
        lookupTable.SetRange(getFieldRange());
        lookupTable.SetNumberOfTableValues(31);
        //lookupTable.SetRampToSCurve();        
        
        lookupTable.SetTableValue(0, 0.03, 0.00, 0.20, 1);
        lookupTable.SetTableValue(1, 0.07, 0.00, 0.31, 1);
        lookupTable.SetTableValue(2, 0.10, 0.00, 0.42, 1);
        lookupTable.SetTableValue(3, 0.11, 0.00, 0.53, 1);
        lookupTable.SetTableValue(4, 0.10, 0.00, 0.64, 1);
        lookupTable.SetTableValue(5, 0.09, 0.00, 0.75, 1);
        lookupTable.SetTableValue(6, 0.06, 0.00, 0.86, 1);
        lookupTable.SetTableValue(7, 0.01, 0.00, 0.97, 1);
        lookupTable.SetTableValue(8, 0.08, 0.13, 1.00, 1);
        lookupTable.SetTableValue(9, 0.22, 0.30, 1.00, 1);
        lookupTable.SetTableValue(10, 0.35, 0.46, 1.00, 1);
        lookupTable.SetTableValue(11, 0.48, 0.60, 1.00, 1);
        lookupTable.SetTableValue(12, 0.61, 0.73, 1.00, 1);
        lookupTable.SetTableValue(13, 0.75, 0.83, 1.00, 1);
        lookupTable.SetTableValue(14, 0.88, 0.93, 1.00, 1);
        lookupTable.SetTableValue(15, 1.00, 1.00, 1.00, 1);
        lookupTable.SetTableValue(16, 1.00, 0.93, 0.88, 1);
        lookupTable.SetTableValue(17, 1.00, 0.83, 0.75, 1);
        lookupTable.SetTableValue(18, 1.00, 0.73, 0.61, 1);
        lookupTable.SetTableValue(19, 1.00, 0.60, 0.48, 1);
        lookupTable.SetTableValue(20, 1.00, 0.46, 0.35, 1);
        lookupTable.SetTableValue(21, 1.00, 0.30, 0.22, 1);
        lookupTable.SetTableValue(22, 1.00, 0.13, 0.08, 1);
        lookupTable.SetTableValue(23, 0.97, 0.00, 0.01, 1);
        lookupTable.SetTableValue(24, 0.86, 0.00, 0.06, 1);
        lookupTable.SetTableValue(25, 0.75, 0.00, 0.09, 1);
        lookupTable.SetTableValue(26, 0.64, 0.00, 0.10, 1);
        lookupTable.SetTableValue(27, 0.53, 0.00, 0.11, 1);
        lookupTable.SetTableValue(28, 0.42, 0.00, 0.10, 1);
        lookupTable.SetTableValue(29, 0.31, 0.00, 0.07, 1);
        lookupTable.SetTableValue(30, 0.21, 0.00, 0.03, 1);
        
        lookupTable.Build();
        
        return lookupTable;
    }

     public vtkPanel cutVolume()
    {
        setCutPlane();
        
        vtkCutter cutter = new vtkCutter();
        cutter.SetInput(reader.GetOutput());
        cutter.SetCutFunction(cutPlane);
        
        vtkPolyDataMapper pdMapper = new vtkPolyDataMapper();
        pdMapper.SetInput(cutter.GetOutput());
        
        vtkActor actor = new vtkActor();
        actor.SetMapper(pdMapper);
        
        vtkPanel cutPanel = new vtkPanel();
        cutPanel.GetRenderer().AddActor(actor);
        
         if (barActor != null)
            cutPanel.GetRenderer().AddActor(barActor);
         
         if (outlineActor != null)
            cutPanel.GetRenderer().AddActor(outlineActor);     
         
        // set panel's background
        cutPanel.GetRenderer().SetBackground(0.1, 0.2, 0.4);
        // reset active camera
        cutPanel.GetRenderer().ResetCamera();
        
        return cutPanel;
    }
}
